package com.schoolvisitors.controller.admin;

import com.alibaba.fastjson2.JSONObject;
import com.schoolvisitors.CheckPermission;
import com.schoolvisitors.common.PageResult;
import com.schoolvisitors.context.AdminContext;
import com.schoolvisitors.context.UserContext;
import com.schoolvisitors.dto.ReservationCubicleByAdminDto;
import com.schoolvisitors.dto.ReservationCubicleDto;
import com.schoolvisitors.entity.Admin;
import com.schoolvisitors.entity.Reservation;
import com.schoolvisitors.entity.User;
import com.schoolvisitors.enums.PermissionEnum;
import com.schoolvisitors.enums.ReservationTypeEnum;
import com.schoolvisitors.repository.ReservationRepository;
import com.schoolvisitors.response.ResultBody;
import com.schoolvisitors.service.CubicleService;
import com.schoolvisitors.service.ReservationService;
import com.schoolvisitors.vo.NotReviewedReservationVo;
import com.schoolvisitors.vo.ReservationVo;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@RequestMapping("/api/v1/admin")
@RestController
public class AdminReservationController {

    private final CubicleService cubicleService;
    private final ReservationService reservationService;
    private final ReservationRepository reservationRepository;

    public AdminReservationController(CubicleService cubicleService, ReservationService reservationService, ReservationRepository reservationRepository) {
        this.cubicleService = cubicleService;
        this.reservationService = reservationService;
        this.reservationRepository = reservationRepository;
    }

//    @GetMapping("/getdReservationsByNotReview")
//    public ResultBody getNotReviewedReservations() {
//        List<NotReviewedReservationVo> cubicleReservations = cubicleService.getNotReviewedReservationsVoByLab(1L);
//        return ResultBody.success(cubicleReservations);
//    }

    @GetMapping("/getReservationsByNotReview")
    public ResultBody getReservationsByNotReview(
            @RequestParam(value = "type") ReservationTypeEnum type,
            @RequestParam("page") int page,
            @RequestParam("size") int size) {
        Admin admin = AdminContext.get();
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("id")));
        Page<Reservation> reservations = reservationService.getReservationsByReviewerAndNotReview(type, admin.getId(), pageable);
        Page<ReservationVo> voPages = reservations.map(ReservationVo::toVo);
        return ResultBody.success(PageResult.bind(voPages));
    }

//    @GetMapping("/getReservations")
//    public ResultBody getReservations(
//            @RequestParam(defaultValue = "1") int page,
//            @RequestParam(defaultValue = "10") int size,
//            @RequestParam(required = false) String search) {
//
//         return ResultBody.success(cubicleService.getReservationsByReviewer(1L, page, size, search));
//    }

    @GetMapping("/getReservations")
    public ResultBody getReservations(
            @RequestParam(value = "type") ReservationTypeEnum type,
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("search") String search) {
        Admin admin = AdminContext.get();
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("id")));
        Page<Reservation> reservations = reservationService.getReservationsByReviewer(type, admin.getId(), search, pageable);
        Page<ReservationVo> voPages = reservations.map(ReservationVo::toVo);
        return ResultBody.success(PageResult.bind(voPages));
    }

    @GetMapping("/getNotOutReservations")
    public ResultBody getNotOutReservations(
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("search") String search) {
        Admin admin = AdminContext.get();
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("id")));
        Page<Reservation> reservations = reservationService.getNotOutReservationByReviewer(admin.getId(), search, pageable);
        Page<ReservationVo> voPages = reservations.map(ReservationVo::toVo);
        return ResultBody.success(PageResult.bind(voPages));
    }

    @PostMapping("/reservationCubicle")
    public ResultBody reservationCubicle(@RequestBody @Valid ReservationCubicleByAdminDto reservationCubicleByAdminDto) {
        ReservationCubicleDto reservationCubicleDto = new ReservationCubicleDto();
        BeanUtils.copyProperties(reservationCubicleByAdminDto, reservationCubicleDto);
        cubicleService.reservationCubicle(reservationCubicleByAdminDto.getUserId(), reservationCubicleDto);
        return ResultBody.success();
    }

    @PostMapping("/rejectReservation")
    public ResultBody rejectReservation(@RequestBody JSONObject json) {
        Long reservationId = json.getLong("reservationId");
        reservationService.rejectReservation(reservationId);
        return ResultBody.success();
    }

    @PostMapping("/approveReservation")
    public ResultBody approveReservation(@RequestBody JSONObject json) {
        Long reservationId = json.getLong("reservationId");
        reservationService.approveReservation(reservationId);
        return ResultBody.success();
    }

    @CheckPermission(PermissionEnum.SYSTEM_ADMIN)
    @GetMapping("/export")
    public void exportCsv(@RequestParam("startTime") LocalDateTime startTime,
                          @RequestParam("endTime") LocalDateTime endTIme,
                          @RequestParam("type") ReservationTypeEnum type,
                          HttpServletResponse response) throws IOException {

        List<Reservation> records = reservationRepository.findByTypeAndCreateAtBetween(type, startTime, endTIme);

        response.setContentType("text/csv");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=records.csv");
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();


        // 写入每一行记录
        writer.println("ID,类型,状态,审核人ID,预约日期,积分,签到时间,签退时间,未签退警告,用户姓名,房间类型,预约时段,仪器名称,取消原因,隔间编号,更新时间,记录创建时间");

        for (Reservation r : records) {
            writer.printf("%d,%s,%s,%d,%s,%d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s%n",
                    r.getId(),
                    r.getType().name(),                                // Enum -> String
                    r.getStatus().name(),
                    r.getReviewerId(),
                    r.getDate(),
                    r.getPoints(),
                    r.getCheckInTime() != null ? r.getCheckInTime().toString() : "",
                    r.getCheckOutTime() != null ? r.getCheckOutTime().toString() : "",
                    r.getNotOutWarn(),
                    r.getUser() != null ? r.getUser().getRealName() : "",
                    r.getRoom() != null ? r.getRoom().getSubType() : "",
                    r.getTimeSlot() != null ? r.getTimeSlot().getStartTime() + " - " + r.getTimeSlot().getEndTime() : "",
                    r.getInstrument() != null ? r.getInstrument().getName() : "",
                    r.getCancelReason() != null ? r.getCancelReason() : "",
                    r.getCubicleNumber() != null ? r.getCubicleNumber() : "",
                    r.getUpdateAt(),
                    r.getCreateAt()
            );
        }


        writer.flush();
        writer.close();
    }
}
